package com.soul.factory;

import com.soul.annotation.RemoteClient;
import com.soul.interceptor.Interceptor;
import com.soul.net.http.HttpService;
import com.soul.proxy.HttpInterface;

import java.io.File;
import java.lang.reflect.Proxy;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 默认http工厂
 */
public class HttpRemoteFactory extends RemoteFactory implements HttpFactory {
    
    private static Map<String,Object> cache = new HashMap<>();
    private static Map<String,String> name_cache = new HashMap<>();
    
    private static List<Interceptor> interceptors = new ArrayList<>();

    /**
     * 接口所在包
     */
    private String packageName;

    private ClassLoader classLoader = this.getClass().getClassLoader();

    public HttpRemoteFactory() {
        super();
    }

    public HttpRemoteFactory(String packageName){
        this.packageName = packageName;
        build();
    }

    private void build() {
        List<Class<?>> classes = resolverInterface();
        if (classes != null){
            for (Class<?> aClass : classes) {
                createProxy(aClass);
            }
        }
    }
    
    private void createProxy(Class<?> clz){
        HttpInterface proxy = new HttpInterface(new HttpService(),interceptors);
        Object o = Proxy.newProxyInstance(classLoader, new Class[]{clz}, proxy);
        cache.put(getCacheName(clz),o);
    }

    private List<Class<?>> resolverInterface(){
        if (packageName == null){
            return null;
        }
        String packagePath = packageName.replaceAll("\\.", "/");
        URL resource = this.getClass().getClassLoader().getResource(packagePath);
        File file = new File(resource.getFile());
        if (file.isDirectory()) {
            List<Class<?>> list = new ArrayList<>();
            File[] files = file.listFiles(it -> it.getName().endsWith(".class"));
            for (int i = 0; i < files.length; i++) {
                File f = files[i];
                String name = f.getName();
                String interName = name.substring(0,name.lastIndexOf("."));
                try {
                    String className = packageName + "." + interName;
                    Class<?> aClass = Class.forName(className);
                    name_cache.put(className,getCacheName(aClass));
                    list.add(aClass);
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
            return list;
        }
        return null;
    }

    @Override
    public <T> T getInterface(Class<T> clz){
        String name = name_cache.get(clz.getName());
        if (name != null){
            return (T) cache.get(name);
        }
        return null;
    }

    public <T> T getInterface(String name){
        return (T) cache.get(name);
    }

    private String getCacheName(Class<?> clz){
        if (clz == null){
            return null;
        }
        String simpleName = clz.getSimpleName();
        String name = simpleName.substring(0,1).toLowerCase() + simpleName.substring(1);
        return name;
    }
    
    public void regist(Class<?> clz){
        RemoteClient annotation = clz.getAnnotation(RemoteClient.class);
        if (annotation != null){
            name_cache.put(clz.getName(),getCacheName(clz));
            createProxy(clz);
        }
    }
    
    public void addInterceptor(Interceptor interceptor){
        interceptors.add(interceptor);
    }
}
